// -*- C++ -*-
/* $Id: SpritePixel.cc 1.1 1998/04/23 17:46:25 atterer Exp $
  __   _
  |_) /|  Copyright Richard Atterer
  | \/|  <atterer@informatik.tu-muenchen.de>
   ` 
  SpritePixel and SpritePixel{1,2,4,8,16,32}bpp classes.
  OSLib needed.

  Only implemented for 4bpp ATM.

  $Log: SpritePixel.cc $
  Revision 1.1  1998/04/23 17:46:25  atterer
  Initial revision

  This program is free software; you can redistribute it and/or modify
  it under the terms of the GNU General Public License as published by
  the Free Software Foundation; either version 2 of the License, or
  (at your option) any later version.

  This program is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  GNU General Public License for more details.

  You should have received a copy of the GNU General Public License
  along with this program; if not, write to the Free Software
  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/

const char* rcsid_spritepixel_cc =
"$Id: SpritePixel.cc 1.1 1998/04/23 17:46:25 atterer Exp $";

#include "SpritePixel.h"
// only for outputting "not implemented" errors:
#include <stdio.h>

typedef unsigned char  byte;
typedef unsigned int   word;
typedef unsigned short hword;
//______________________________________________________________________

SpritePixel::SpritePixel(const Sprite& spr, int x = 0, int y = 0) {
  sprdata = &spr.raw();
  init(*this, x, y);
}

SpritePixel::SpritePixel(const osspriteop_header& rawsprite,
    int x = 0,int y = 0) {
  sprdata = const_cast<osspriteop_header*>(&rawsprite);
  init(*this, x, y);
}

bool SpritePixel::init(SpritePixel& pixel, int x = 0, int y = 0) {
  int bpp; // duplicates code of Sprite::bpp()
  unsigned modeword = unsigned(pixel.sprdata->mode);
  if (modeword & 0xf8000000)
    bpp = int(modeword >> 27) - 1; // new format
  else // old format
    bpp = int(Sprite::modebpp[modeword / 4] >> (modeword & 3) * 2) & 3;

  switch (bpp) {
    case 0: return false;
    case 1: return false;
    case 2:
      pixel.boolxy = &SpritePixel4bpp::xy;
      pixel.intleft  = &SpritePixel4bpp::left;
      pixel.intright = &SpritePixel4bpp::right;
      pixel.intup    = &SpritePixel4bpp::up;
      pixel.intdown  = &SpritePixel4bpp::down;
      pixel.voidleft  = &SpritePixel4bpp::fleft;
      pixel.voidright = &SpritePixel4bpp::fright;
      pixel.voidup    = &SpritePixel4bpp::fup;
      pixel.voiddown  = &SpritePixel4bpp::fdown;
      pixel.intcol = &SpritePixel4bpp::col;
      pixel.xres = pixel.sprdata->width * 8 + pixel.sprdata->right_bit / 4
          - pixel.sprdata->left_bit / 4;
      break;
    case 3: return false;
    case 4: return false;
    case 5: return false;
  }
  return pixel.xy(x, y);
}
//______________________________________________________________________

bool SpritePixel4bpp::xy(SpritePixel* pixel, int x, int y) {
  pixel->xpos = x; pixel->ypos = y; // set position even if illegal
  osspriteop_header* rawsprite = pixel->sprdata;
  pixel->pos = static_cast<word*>(
      static_cast<byte*>(rawsprite) + rawsprite->image);
  // move to line
  pixel->pos += (rawsprite->width + 1) * (rawsprite->height - y);
  //DEBUG(printf("xy: first word of line=%X\n", *pos))
  pixel->pos += x >> 3; // move to column
  if (x < 0 || y < 0 || x > pixel->xres || y > rawsprite->height)
    return false;
  else
    return true;
}

int SpritePixel4bpp::left(SpritePixel* pixel) {
  int shift = --pixel->xpos & 7;
  if (shift == 7) pixel->pos--;
  if (pixel->xpos < 0) return -1;
  return *(pixel->pos) >> shift * 4 & 15;
}
int SpritePixel4bpp::right(SpritePixel* pixel) {
  int shift = ++pixel->xpos & 7;
  if (shift == 0) pixel->pos++;
  if (pixel->xpos > pixel->xres) return -1;
  return *pixel->pos >> shift * 4 & 15;
}
int SpritePixel4bpp::up(SpritePixel* pixel) {
  pixel->ypos++;
  pixel->pos -= pixel->sprdata->width + 1;
  if (pixel->ypos > pixel->sprdata->height) return -1;
  return *pixel->pos >> (pixel->xpos & 7) * 4 & 15;
}
int SpritePixel4bpp::down(SpritePixel* pixel) {
  pixel->ypos--;
  pixel->pos += pixel->sprdata->width + 1;
  if (pixel->ypos < 0) return -1;
  return *pixel->pos >> (pixel->xpos & 7) * 4 & 15;
}
void SpritePixel4bpp::fleft(SpritePixel* pixel) {
  int shift = --pixel->xpos & 7;
  if (shift == 7) pixel->pos--;
  return;
}
void SpritePixel4bpp::fright(SpritePixel* pixel) {
  int shift = ++pixel->xpos & 7;
  if (shift == 0) pixel->pos++;
  return;
}
void SpritePixel4bpp::fup(SpritePixel* pixel) {
  pixel->ypos++;
  pixel->pos -= pixel->sprdata->width + 1;
  return;
}
void SpritePixel4bpp::fdown(SpritePixel* pixel) {
  pixel->ypos--;
  pixel->pos += pixel->sprdata->width + 1;
  return;
}
int SpritePixel4bpp::col(SpritePixel* pixel) {
  return (*pixel->pos >> (pixel->xpos & 7) * 4) & 15;
}
